﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Net;
using System.Resources;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
//using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using DevicesInt;
using mshtml;
using HorizontalAlignment = System.Windows.HorizontalAlignment;

namespace _3S_Cam
{
    /// <summary>
    /// Логика взаимодействия для CamControl.xaml
    /// </summary>
    public partial class CamControl : IDisposable
    {

        public CamController Controller { get; private set; }
        private readonly ResourceManager _rm = new ResourceManager(typeof(LocalResources._3S_Cam_Locale));
        private string ConnectAddress { get { return "http://" + Controller.IpAddress; } }
        private const int CheckTimeout = 2500;
        private string ConnectingString = "Connecting...";
        private string NoConnectionString = "No connection";
        private string CurInfoString;
        private readonly WebBrowser _camWeb;
        private HttpWebRequest _wr;
        private System.Threading.Timer _tim;
        private bool _isCamVisible = false;
        private readonly CultureInfo _curCulture;

        public CamControl(CamController controller, CultureInfo cultureInfo)
        {
            InitializeComponent();
            //Current culture
            DeviceControl.CurrentCulture = cultureInfo;
            if (DeviceControl.CurrentCulture == null)
            {
                var cul = CultureInfo.CurrentUICulture;
                if (cul.Name.Contains("ru") || cul.Name.Contains("RU"))
                {
                    DeviceControl.CurrentCulture = CultureInfo.GetCultureInfo("ru");
                }
                else
                {
                    DeviceControl.CurrentCulture = cul;
                }
            }
            _curCulture = DeviceControl.CurrentCulture;
            Controller = controller;
            _camWeb = new WebBrowser { ScrollBarsEnabled = false, ScriptErrorsSuppressed = true };
            _camWeb.DocumentCompleted += (sender, args) =>
            {
                if (_camWeb.ReadyState != WebBrowserReadyState.Complete)
                    return;
                ProcessDocument(_camWeb.Document);
            };
            IpLabel.Content = controller.IpAddress;
            InfoLabel.Content = ConnectingString;
            CurInfoString = ConnectingString;
            Init();
        }

        void Init()
        {
            //Loaded
            var host = new System.Windows.Forms.Integration.WindowsFormsHost();
            host.Child = _camWeb;
            host.VerticalAlignment = VerticalAlignment.Center;
            host.HorizontalAlignment = HorizontalAlignment.Center;
            CamContainer.Children.Add(host);
            StartTimer();
            //--------------------------------------
            RecordButton.Visibility = Visibility.Collapsed;
            SnapshotButton.Visibility = Visibility.Collapsed;
            FolderButton.Visibility = Visibility.Collapsed;
            AudioOutButton.Visibility = Visibility.Collapsed;
            SetImageToButtonContent(FolderButton, Properties.Resources.folder_download);
            SetImageToButtonContent(SnapshotButton, Properties.Resources.photo);
            SetImageToButtonContent(OpenBrowserButton, Properties.Resources.web_browser);
            //Locale
            ConnectingString = _rm.GetString("Connecting", _curCulture) + "...";
            NoConnectionString = _rm.GetString("NoConnection", _curCulture);

            RecordButton.ToolTip = new System.Windows.Controls.ToolTip {Content = _rm.GetString("StartRecord", _curCulture)};
            SnapshotButton.ToolTip = new System.Windows.Controls.ToolTip { Content = _rm.GetString("Snapshot", _curCulture) };
            FolderButton.ToolTip = new System.Windows.Controls.ToolTip { Content = _rm.GetString("SelectFolder", _curCulture) };
            AudioOutButton.ToolTip = new System.Windows.Controls.ToolTip { Content = _rm.GetString("AudioOut", _curCulture) };
            OpenBrowserButton.ToolTip = new System.Windows.Controls.ToolTip { Content = _rm.GetString("OpenInBrowser", _curCulture) };
        }

        public bool CheckConnecionSync()
        {
            UpdateRequester();
            try
            {
                var resp = (HttpWebResponse)_wr.GetResponse();
                if (resp.StatusCode == HttpStatusCode.ServiceUnavailable)
                    return false;
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        void CheckConnection()
        {
            //if (_wr == null)
            {
                UpdateRequester();
            }

            try
            {
                _wr.BeginGetResponse(ar =>
                    {
                        try
                        {
                            using (var resp = (HttpWebResponse) _wr.EndGetResponse(ar))
                            {
                                if (resp.StatusCode == HttpStatusCode.ServiceUnavailable)
                                    DoIfNotConnected();
                            }
                            //var resp = (HttpWebResponse) _wr.EndGetResponse(ar);
                            //resp.Close();
                            DoIfConnected();
                        }
                        catch (ObjectDisposedException)
                        {
                            return;
                        }
                        catch (ArgumentException)
                        {
                            _tim.Change(0, CheckTimeout);
                            return;
                        }
                        catch (Exception)
                        {
                            DoIfNotConnected();
                            return;
                        }
                        
                    }, null);
            }
            catch (Exception)
            {
                UpdateRequester();
                DoIfNotConnected();
            }
        }

        void ContinueTimer()
        {
            try
            {
                _tim.Change(0, CheckTimeout);
            }
            catch (ObjectDisposedException)
            {
                //_camWeb.Invoke(new Action(() =>
                //    {
                //        _camWeb.Dispose();
                //    }));
                return;
            }
            
        }

        void UpdateRequester()
        {
            
            _wr = WebRequest.Create(ConnectAddress) as HttpWebRequest;
            _wr.Timeout = 4000;
            _wr.KeepAlive = false;
        }

        void DoIfConnected()
        {
            if (!_isCamVisible)
            {
                _camWeb.Invoke(new Action(() =>
                    {

                        ControlsContainer.Visibility = Visibility.Visible;
                        NoConnectionContainer.Visibility = Visibility.Collapsed;
                    }));
                Connect();
                _isCamVisible = true;
            }
            else
            {
                _camWeb.Invoke(new Action(() => ProcessDocument(_camWeb.Document)));
            }
            ContinueTimer();
        }

        void DoIfNotConnected()
        {
            if (_isCamVisible || CurInfoString == ConnectingString)
            {
                _camWeb.Invoke(new Action(() =>
                    {
                        InfoLabel.Content = NoConnectionString;
                        CurInfoString = NoConnectionString;
                        ControlsContainer.Visibility = Visibility.Collapsed;
                        NoConnectionContainer.Visibility = Visibility.Visible;
                    }));
                _isCamVisible = false;
            }
            ContinueTimer();
        }

        private const int INTERNET_OPTION_END_BROWSER_SESSION = 42;

        [DllImport("wininet.dll", SetLastError = true)]
        private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer,
                                                     int lpdwBufferLength);

        void Connect()
        {
            //DeleteCache.DeleteEntry(ConnectAddress);
            //InternetSetOption(IntPtr.Zero, INTERNET_OPTION_END_BROWSER_SESSION, IntPtr.Zero, 0);
            _camWeb.Navigate(ConnectAddress);
        }

        void StartTimer()
        {
            _tim = new System.Threading.Timer(TimCallback, null, 0, CheckTimeout);
        }

        private void TimCallback(object state)
        {
            _tim.Change(Timeout.Infinite, Timeout.Infinite);
            CheckConnection();      //Check connection with camera
        }

        //HtmlElement _recordButtonElement;
        HtmlElement _recordButtonElement;
        HtmlElement _folderElement;
        HtmlElement _audioOutElement;
        HtmlElement _snapShotElement;

        void ProcessDocument(HtmlDocument doc)
        {
            //HtmlElement camViewerElement;


            if (doc == null)
                return;
            var els = new List<HtmlElement>();
            var element = doc.GetElementById("CamViewerTd");

            if (element == null)
            {
                if (doc.Window.Frames.Count < 1)
                {
                    return;
                }
                var f = doc.Window.Frames[0];
                var doc1 = f.Document;
                if (doc1.Body != null)
                    doc1.Body.Style = "overflow:hidden";
                var dt1 = DateTime.Now;
                element = doc1.GetElementById("CamViewerTd");                   //Viewer
                _recordButtonElement = doc1.GetElementById("RecordBtn");        //Record button
                if (_recordButtonElement != null)
                {
                    var but = RecordButton;
                    const string on = "3s_Rec_up";
                    const string off = "3s_Rec_down";
                    var src = _recordButtonElement.GetAttribute("src");
                    if (!string.IsNullOrEmpty(src))
                    {
                        if (src.Contains(on))
                        {
                            if (!ReferenceEquals(but.Tag, on))
                            {
                                SetImageToButtonContent(but, Properties.Resources.record);
                                var toolTip = RecordButton.ToolTip as System.Windows.Controls.ToolTip;
                                if (toolTip != null)
                                    toolTip.Content =
                                        _rm.GetString("StartRecord", _curCulture);
                                but.Tag = on;
                            }
                        }
                        else if (src.Contains(off))
                            if (!ReferenceEquals(but.Tag, off))
                            {
                                SetImageToButtonContent(but, Properties.Resources.pause);
                                var toolTip = RecordButton.ToolTip as System.Windows.Controls.ToolTip;
                                if (toolTip != null)
                                    toolTip.Content =
                                        _rm.GetString("StopRecord", _curCulture);
                                but.Tag = off;
                            }

                    }
                }
                SetButtonVisibility(RecordButton, _folderElement != null);
                _folderElement = doc1.GetElementById("PathBtn");                //Folder button
                SetButtonVisibility(FolderButton, _folderElement != null);
                _snapShotElement = doc1.GetElementById("SnapShotBtn");          //SnapShot button
                SetButtonVisibility(SnapshotButton, _snapShotElement != null);
                _audioOutElement = doc1.GetElementById("audio_out");            //AudioOut button
                if (_audioOutElement != null)
                {
                    var but = AudioOutButton;
                    const string on = "3s_Speaker_on";
                    const string off = "3s_Speaker_off";
                    var src = _audioOutElement.GetAttribute("src");
                    if (!string.IsNullOrEmpty(src))
                    {
                        if (src.Contains(on))
                        {
                            if (!ReferenceEquals(but.Tag, on))
                            {
                                SetImageToButtonContent(but, Properties.Resources.sound_on);
                                but.Tag = on;
                            }
                        }
                        else if (src.Contains(off))
                            if (!ReferenceEquals(but.Tag, off))
                            {
                                SetImageToButtonContent(but, Properties.Resources.sound_off);
                                but.Tag = off;
                            }
                    }
                }
                SetButtonVisibility(AudioOutButton, _audioOutElement != null);
                var dt2 = DateTime.Now;
                if (_folderElement != null && element != null)
                {
                    var ts = dt2 - dt1;
                }

            }
            if (element == null)
                return;

            element.ScrollIntoView(true);
            int right = element.ClientRectangle.Right;
            int bottom = element.ClientRectangle.Bottom;

            _camWeb.Height = bottom;
            _camWeb.Width = right;
        }

        void SetButtonVisibility(System.Windows.Controls.Button but, bool isVisible)
        {
            if (isVisible)
            {
                if (but.Visibility == Visibility.Visible)
                    return;
                but.Visibility = Visibility.Visible;
            }
            else
            {
                if(but.Visibility != Visibility.Visible)
                    return;
                but.Visibility = Visibility.Collapsed;
            }

        }

        void SetImageToButtonContent(System.Windows.Controls.Button but, Bitmap image)
        {
            ImageSource folder = Imaging.CreateBitmapSourceFromHBitmap(image.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
            but.Content = new System.Windows.Controls.Image { Source = folder };
        }

        public void Dispose()
        {
            _camWeb.Dispose();
            _tim.Dispose();
        }

        private void RecordButton_OnClick(object sender, RoutedEventArgs e)
        {
            if (_recordButtonElement != null)
                _recordButtonElement.InvokeMember("click");
        }

        private void FolderButton_OnClick(object sender, RoutedEventArgs e)
        {
            if (_folderElement != null)
                _folderElement.InvokeMember("click");
        }

        private void SnapshotButton_OnClick(object sender, RoutedEventArgs e)
        {
            if (_snapShotElement != null)
                _snapShotElement.InvokeMember("click");
        }

        private void AudioOutButton_OnClick(object sender, RoutedEventArgs e)
        {
            if (_audioOutElement != null)
                _audioOutElement.InvokeMember("click");
        }

        private void OpenBrowserButton_OnClick(object sender, RoutedEventArgs e)
        {
            Process.Start(ConnectAddress);
        }
    }
}
